<?php

namespace app\admin\controller\fastflow\flow;

use app\admin\model\fastflow\flow\Bill;
use app\admin\model\fastflow\flow\EbillCopy;
use app\admin\model\fastflow\flow\EbillLog;
use app\admin\model\fastflow\Signature;
use app\common\controller\Backend;
use think\Db;
use think\Exception;
use think\exception\DbException;
use think\exception\PDOException;
use think\exception\ValidateException;
use think\Lang;
use think\Loader;


/**
 * 流程运行
 *
 * @icon fa fa-o
 */
class Ebill extends Backend
{
    protected $model = null;
    protected $noNeedRight = [
        'preview',
        'word2html',
        'getEbillList'
    ];
    protected $api;
    protected $auth = null;

    public function _initialize()
    {
        parent::_initialize();
        $this->model = new \app\admin\model\fastflow\flow\Ebill;
    }

    public function index()
    {
        $bill_model = new \app\admin\model\fastflow\flow\Bill;
        if ($this->request->isAjax()) {
            $bill_table = '';
            if ($this->request->has('bill')) {
                $bill_table = input('bill');
            } else {
                $bill_id = input('bill_id');
                if ($bill_id) {
                    $bill_row = $bill_model->find($bill_id);
                    if (!$bill_row) {
                        return ['code' => 0, 'msg' => '未找到单据'];
                    }
                    $bill_table = $bill_row['bill_table'];
                }
            }

            $ebill_rows = $this->model->field(['id', 'title', 'info', 'thumbnail', 'thumb_width', 'thumb_height', 'createtime'])->where(['bill' => $bill_table])->select();
            return ['code' => 1, 'msg' => '获取成功', 'ebills' => $ebill_rows];
        }

        $bills = $bill_model->field(['id', 'bill_name', 'bill_table'])->select();
        $this->view->assign(['bills' => $bills]);
        return $this->view->fetch();
    }

    /**
     * 添加
     *
     * @return string
     * @throws \think\Exception
     */
    public function add()
    {
        if (false === $this->request->isPost()) {
            $bill_id = input('bill_id');
            if ($bill_id == null) {
                return '参数错误：未传递单据ID';
            }
            $this->view->assign(['bill_id' => $bill_id]);
            return $this->view->fetch();
        }

        $params = $this->request->post('');
        $params_row = $params['row'];
        unset($params['row']);
        $params = array_merge($params_row, $params);

        if ($params['title'] == '') {
            $this->error('请填写表单名称');
        }
        if ($params['file'] == '') {
            $this->error('文件路径不能为空');
        }

        $bill_id = $params['bill'];
        $bill_row = (new \app\admin\model\fastflow\flow\Bill())->find($bill_id);
        if (!$bill_row) {
            $this->error('未查询到相应单据');
        }

        $params['md5'] = md5_file(ltrim($params['file'], '/'));

        $params['bill'] = $bill_row['bill_table'];
        $ebill_rows = $this->model->where(['bill' => $params['bill']])->select();
        foreach ($ebill_rows as $ebill_row) {
            if ($params['md5'] == $ebill_row['md5']) {
                $this->error('该单据已存在相同电子表单');
            }
        }

        if (empty($params)) {
            $this->error(__('Parameter %s can not be empty', ''));
        }
        $params = $this->preExcludeFields($params);

        if ($this->dataLimit && $this->dataLimitFieldAutoFill) {
            $params[$this->dataLimitField] = $this->auth->id;
        }
        $result = false;
        Db::startTrans();
        try {
            //是否采用模型验证
            if ($this->modelValidate) {
                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.add' : $name) : $this->modelValidate;
                $this->model->validateFailException()->validate($validate);
            }
            $result = $this->model->allowField(true)->save($params);
            Db::commit();
        } catch (ValidateException|PDOException|Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
        if ($result === false) {
            $this->error(__('No rows were inserted'));
        }
        $this->success('添加成功');
    }


    /**
     * 编辑
     *
     * @param $ids
     * @return string
     * @throws DbException
     * @throws \think\Exception
     */
    public function edit($ids = null)
    {
        $row = $this->model->get($ids);
        if (!$row) {
            $this->error(__('No Results were found'));
        }
        $adminIds = $this->getDataLimitAdminIds();
        if (is_array($adminIds) && !in_array($row[$this->dataLimitField], $adminIds)) {
            $this->error(__('You have no permission'));
        }
        if (false === $this->request->isPost()) {
            $this->view->assign('row', $row);
            return $this->view->fetch();
        }
        $params = $this->request->post();

        $params_row = $params['row'];
        unset($params['row']);
        $params = array_merge($params_row, $params);
        if ($params['title'] == '') {
            $this->error('请填写表单名称');
        }
        if ($params['file'] == '') {
            $this->error('文件路径不能为空');
        }
        $params['md5'] = md5_file(ltrim($params['file'], '/'));

        $ebill_rows = $this->model->where(['bill' => $row['bill']])->select();
        foreach ($ebill_rows as $ebill_row) {
            if ($ids != $ebill_row['id'] && $params['md5'] == $ebill_row['md5']) {
                $this->error('该单据已存在相同电子表单');
            }
        }

        if (empty($params)) {
            $this->error(__('Parameter %s can not be empty', ''));
        }
        $params = $this->preExcludeFields($params);
        $result = false;
        Db::startTrans();
        try {
            //是否采用模型验证
            if ($this->modelValidate) {
                $name = str_replace("\\model\\", "\\validate\\", get_class($this->model));
                $validate = is_bool($this->modelValidate) ? ($this->modelSceneValidate ? $name . '.edit' : $name) : $this->modelValidate;
                $row->validateFailException()->validate($validate);
            }
            $result = $row->allowField(true)->save($params);
            Db::commit();
        } catch (ValidateException|PDOException|Exception $e) {
            Db::rollback();
            $this->error($e->getMessage());
        }
        if (false === $result) {
            $this->error(__('No rows were updated'));
        }
        $this->success('修改成功');
    }

    //文件路径优先，同时存在id和路径，选择路径
    public function preview()
    {
        $path = null;
        $row = [];
        $action = input('action');

        if ($action == 'detail') {//查看电子表单详情
            $bill = input('bill');
            $bill_id = input('bill_id');
            $ebill_copy = $this->getEbillCopy($bill, $bill_id);

            if ($ebill_copy) {
                //查询是否有发起签章
                $signature = (new Signature())->where(['bill' => $bill, 'bill_id' => $bill_id])->find();
                if ($signature) {
                    $this->view->assign(['code' => 1, 'hasSignature' => true, 'ebill' => $signature['ebill'], 'size' => ['width' => $signature['ebill_width'], 'height' => $signature['ebill_height']], 'ebill_title' => $ebill_copy['title']]);
                    $this->assignconfig(['hasSignature' => true]);
                    return $this->view->fetch();
                }
                //为无签章时提供电子表单标题
                $bill_row = (new Bill())->where(['bill_table' => $bill])->find();
                $this->assignconfig(['bill_name' => $bill_row['bill_name']]);
                //传递二维码数据
                $configModel = new \app\admin\model\fastflow\flow\Config();
                $config_qrcode = $configModel->where(['name' => 'qrcode'])->find();
                $config_qrcodepos = $configModel->where(['name' => 'qrcodepos'])->find();
                $config_qrcodesize = $configModel->where(['name' => 'qrcodesize'])->find();
                $detail_url = url('/fastflow/flow/flow/detail', ['bill' => $bill, 'bill_id' => $bill_id], false, true);
                $this->assignconfig(['qrcode' => $config_qrcode['value'], 'qrcodepos' => $config_qrcodepos['value'], 'qrcodesieze' => $config_qrcodesize['value'], 'bill' => $bill, 'bill_id' => $bill_id, 'detail_url' => $detail_url]);
                ///

                $path = $ebill_copy['file'];
            }
        } elseif ($action == 'preview') {
            if ($this->request->has('file')) {//新增电子表单
                $path = input('file');
            } elseif ($this->request->has('id')) {//编辑电子表单、发起时添加电子表单
                $ebill = $this->model->where(['id' => input('id')])->find();
                if ($ebill) {
                    $path = $ebill['file'];
                    $this->assignconfig(['ebill_title' => $ebill['title']]);
                }
            }
        }

        if ($path == null) {
            $this->view->assign(['code' => 0, 'msg' => '参数错误：未找到文件']);
            return $this->view->fetch();
        }

        if (input('row/a')) {
            $row = input('row/a');
        }
        $row = $this->updateBillRow(input('bill'), input('bill_id'), $row);

        $result = $this->word2html($path, $row);

        if (!$result['code']) {
            $this->view->assign(['code' => 0, 'msg' => $result['msg']]);
        } else {
            $content = $result['content'];

            $style_pattern = '/(?<=<style>)[\s\S]*(?=<\/style>)/';
            preg_match($style_pattern, $content, $style);

            $body_pattern = '/(?<=<body>)[\s\S]*(?=<\/body>)/';
            preg_match($body_pattern, $content, $body);

            $this->assignconfig(['hasSignature' => false]);
            $this->view->assign(['code' => 1, 'hasSignature' => false, 'style' => $style[0], 'ebill' => $body[0], 'size' => $result['sizeInfo']]);
        }
        return $this->view->fetch();
    }


    private function getBillController($bill)
    {
        $billRow = (new \app\admin\model\fastflow\flow\Bill())->where(['bill_table' => $bill])->find();
        if ($billRow) {
            return $billRow['controller'];
        }
        return '';
    }

    private function getBillModelInstance($bill)
    {
        $controller = $this->getBillController($bill);
        $modelUrl = '\app\\' . $this->request->module() . '\model\\' . str_replace('/', '\\', $controller);
        if (class_exists($modelUrl)) {
            $instance = new $modelUrl;
            return $instance;
        }
        return false;
    }

    /**
     * 加载语言文件
     * @param string $name
     */
    protected function loadlang($name)
    {
        $name = Loader::parseName($name);
        $name = preg_match("/^([a-zA-Z0-9_\.\/]+)\$/i", $name) ? $name : 'index';
        $lang = $this->request->langset();
        $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';
        Lang::load(APP_PATH . $this->request->module() . '/lang/' . $lang . '/' . str_replace('/_', '/', str_replace('.', '/', $name)) . '.php');
    }

    /**
     * 更新单据行数据
     * @param $bill 单据表名
     * @param $bill_id 单据id
     * @param $params 用户提交数据
     */
    private function updateBillRow($bill, $bill_id, $params)
    {
        $params = $params ? $params : [];
        $bill_row = [];

        $bill_model_instance = $this->getBillModelInstance($bill);
        if (!$bill_model_instance) {
            return $params;
        }

        $bill_row = $bill_model_instance->find($bill_id);
        $bill_row = $bill_row ? $bill_row->toArray() : [];

        $row = array_merge($bill_row, $params);

        //转换数值为文字
        //加载单据语言文件
        $controller = $this->getBillController($bill);
        $this->loadlang($controller);

        foreach ($row as $key => &$value) {
            if (is_array($value)) {//去除元素内的数组
                $value = '';
            }
            $method = 'get' . Loader::parseName($key, 1) . 'TextAttr';
            if (method_exists($bill_model_instance, $method)) {
                $value = call_user_func([$bill_model_instance, $method], $value, $row);
            }
        }

        return $row;
    }


    /**
     * word转html，可替换模板变量
     * @param $file 文件路径
     * @param null $templateData 模板变量数据
     * @param bool $clearVariable 是否清除未替换变量，如${name}字符串
     * @return array code 1=成功
     * @throws \PhpOffice\PhpWord\Exception\CopyFileException
     * @throws \PhpOffice\PhpWord\Exception\CreateTemporaryFileException
     * @throws \PhpOffice\PhpWord\Exception\Exception
     */
    public function word2html($file, $templateData = [], $clearVariable = true)
    {
        $file = ltrim($file, '/');

        if (!file_exists($file)) {
            return ['code' => 0, 'msg' => '文件不存在'];
        }

        \think\Loader::addNamespace('PhpOffice\PhpWord', ADDON_PATH . 'fastflow' . DS . 'library' . DS . 'PHPWord-master' . DS . 'src' . DS . 'PhpWord' . DS);
        \think\Loader::addNamespace('Laminas\Escaper', ADDON_PATH . 'fastflow' . DS . 'library' . DS . 'laminas-escaper' . DS . 'src' . DS);

        if (is_array($templateData)) {
            $file_temp = 'uploads/' . md5(uniqid(mt_rand(), true)) . '.docx';
            try {
                $templateProcessor = new \PhpOffice\PhpWord\TemplateProcessor($file);
                $templateProcessor->setValue(array_keys($templateData), array_values($templateData));//传值
                $templateProcessor->saveAs($file_temp);
            } catch (Exception $e) {
                if (file_exists($file_temp)) {
                    unlink($file_temp);
                }
                return ['code' => 0, 'msg' => '文件格式错误，请检查模板文件是否为Word2007及更高版本格式'];
            }
        }

        try {
            $phpWord = \PhpOffice\PhpWord\IOFactory::load($file_temp);
            $objWriter = \PhpOffice\PhpWord\IOFactory::createWriter($phpWord, 'HTML');
            if (file_exists($file_temp)) {
                unlink($file_temp);
            }
        } catch (Exception $e) {
            if (file_exists($file_temp)) {
                unlink($file_temp);
            }
            return ['code' => 0, 'msg' => '文件格式错误，请检查模板文件是否为Word2007及更高版本格式'];
        }

        $section = $phpWord->getSection(0);//目前只获取第一个分页样式，暂未处理多页样式，一个分页可包含多页，分页之间以分页符分割
        $style = $section->getStyle();

        $firstSectionWidth = round(((int)$style->getPageSizeW()) / 1440, 2);//宽，单位英寸in
        $firstSectionHeight = round(((int)$style->getPageSizeH()) / 1440, 2);//高
        $firstSectionmarginTop = round(((int)$style->getMarginTop()) / 1440, 2);//上边距
        $firstSectionmarginRight = round(((int)$style->getMarginRight()) / 1440, 2);//右边距
        $firstSectionmarginBottom = round(((int)$style->getMarginBottom()) / 1440, 2);//下边距
        $firstSectionmarginLeft = round(((int)$style->getMarginLeft()) / 1440, 2);//左边距

        $sizeInfo = [
            'width'  => $firstSectionWidth,
            'height' => $firstSectionHeight,
            'left'   => $firstSectionmarginLeft,
            'right'  => $firstSectionmarginRight,
            'top'    => $firstSectionmarginTop,
            'bottom' => $firstSectionmarginBottom
        ];

        $content = $objWriter->getContent();

        if ($clearVariable) {
            $variable_pattern = '/\${[\s\S]*?}/';
            $content = preg_replace($variable_pattern, '', $content);
        }
        return ['code' => 1, 'msg' => '转换成功', 'content' => $content, 'sizeInfo' => $sizeInfo];
    }

    public function appendEbill($bill_id, $ebill_id)
    {
        $ebill_row = $this->model->find($ebill_id)->toArray();
        $ebill_copy_model = new EbillCopy();
        if ($ebill_row) {
            unset($ebill_row['id']);
            unset($ebill_row['createtime']);
            unset($ebill_row['updatetime']);
            $ebill_row['bill_id'] = $bill_id;
            $ebill_copy_model->insert($ebill_row);
        }
    }

    private function getEbillCopy($bill, $bill_id)
    {
        $ebill_copy = (new EbillCopy())->where(['bill' => $bill, 'bill_id' => $bill_id])->find();
        return $ebill_copy;
    }


    public function getEbillCopyId($bill, $bill_id)
    {
        $ebill_copy = $this->getEbillCopy($bill, $bill_id);
        if ($ebill_copy) {
            $ebill_copy = $ebill_copy->toArray();
            return $ebill_copy['id'];
        }
        return null;
    }

    public function getEbillList()
    {
        $bill_model = new \app\admin\model\fastflow\flow\Bill;
        $bill_table = '';
        if ($this->request->has('bill')) {
            $bill_table = input('bill');
        } else {
            $bill_id = input('bill_id');
            if ($bill_id) {
                $bill_row = $bill_model->find($bill_id);
                if (!$bill_row) {
                    return ['code' => 0, 'msg' => '未找到单据'];
                }
                $bill_table = $bill_row['bill_table'];
            }
        }

        $ebill_rows = $this->model->field(['id', 'title', 'info', 'thumbnail', 'thumb_width', 'thumb_height', 'createtime'])->where(['bill' => $bill_table])->select();
        return ['code' => 1, 'msg' => '获取成功', 'ebills' => $ebill_rows];
    }

}